/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/


/**
 * @brief Interface of inner operations of class symbol table and builder.
 *
 * @author  WXQ#XDU
 * @date    2024.12
 */

#pragma once

#ifndef AMCC__STB_INNER_H
#define AMCC__STB_INNER_H

#include "../../include/amcc_error.h"
#include "../../include/amcc_log.h"
#include "../../include/amcc_stack.h"
#include "../../include/amcc_refcount.h"
#include "../../include/tree.h"
#include "../../include/symtable.h"
#include "../../include/symentry.h"
#include "../../include/typesys.h"

AMCC_DECL_BEGIN

#define  STB_ASSUME_TYPE    TK_TYPE_INT


/**
 * @brief Creates a new symbol table.
 *
 * @param ownerTreeNode  pointer to tree node specified my owner information
 * @param parentPtr      pointer to my parent symbol table
 * @return On success, return the new symbol table.
 * @return On failure, return null.
 */
extern t_symtable_ptr symtable_new(t_tree_ptr  ownerTreeNode,
                                   t_symtable_ptr parentPtr);

/**
 * @brief Creates a new symtable entry for a variable,
 *        and put it into the specified symbol table.
 *
 * @param pThis      pointer to the target symbol table
 * @param varType    type of variable
 * @param definitionNode    pointer to the tree node which contains
 *                          the name of variable
 * @param memory_offset     the memory address of this variable
 * @param memory_size       size of the memory of this variable
 * @param initializerNode   pointer to the initializer tree node
 *                          for this variable
 *
 * @return On success, return the new created symbol table entry.
 */
t_symentry_ptr symtable_putVarDefine(t_symtable_ptr pThis,
                                     t_type_ptr varType,
                                     t_tree_ptr definitionNode,
                                     size_t     memory_offset,
                                     t_tree_ptr initializerNode);

/**
 * @brief Creates a new symtable entry for a function
 *        and put it into the specified symbol table.
 *
 * @param pThis          pointer to the target symbol table
 * @param definitionNode pointer to the tree node which contains the
 *                       name of function
 * @param funcSymInfo    pointer to the information of this function
 *
 * @return On success, return the new created symbol table entry.
 */
extern t_symentry_ptr symtable_putFuncDefine(t_symtable_ptr pThis,
                                             t_tree_ptr definitionNode,
                                             t_func_symInfo_ptr funcSymInfo);

/**
 * @brief Creates a new symtable entry for a label
 *        and put it into the specified symbol table.
 *
 * @param pThis          pointer to the target symbol table
 * @param definitionNode pointer to the tree node which contains the
 *                       name of label
 *
 * @return On success, return the new created symbol table entry.
 */
extern t_symentry_ptr symtable_putLabelDefine(t_symtable_ptr pThis,
                                              t_tree_ptr definitionNode);

// Type of function info in scope-stack
typedef struct function_info {
    EnumTokenKind       returnType;     // type of the return value
    const char *        funcName;
    t_func_symInfo_ptr  funcSymInfoPtr; // entry for function
    t_symtable_ptr      symTablePtr;    // symbol table of this function

    // all un-resolved labels in current function,
    // underlying type is t_list<tree-node-labelName>
    //
    // These items will be immediately resolved after analyzing
    // its function-definition.
    t_list  undefinedLabels;
} t_funcinfo, * t_funcinfo_ptr;


// Type of elements in scope-stack
typedef struct scope_stack_item {
    t_symtable_ptr  symtablePtr;     // current symbol table
    t_funcinfo_ptr  currFuncInfoPtr; // to support nested func
} t_stack_item, * t_stack_item_ptr;


// Type of symbol-table builder
struct symbol_table_builder {
    t_tree_listener base ;   // instance of base class

// extended attributes

    int             nErrors; // number of errors during building sym-tables
    t_symtable_ptr  symtableRootPtr; // the top-most symbol table
    t_tree_ptr      treeRoot;        // root of parse tree

    // A stack keeps the scope path, aka the path in symbol table tree.
    // Each element is a pointer to an instance of class t_stack_item.
    t_stack         scopeStack;

    // Attributes bounded to my interesting tree nodes.
    // The KEY is a tree node, the VALUE is an instance of
    // class t_attr_directDeclarator  below.
    t_treemap_ptr   nodeAttributes;

    // Drawing on the famous "back-patching" technique, this
    // symtable-builder uses a linked list to record all
    // un-resolved function names that are used in expressions;
    // the underlying type is t_list<tree-node-functionCall>
    t_list  undefinedFunctions;


// extra members for analysis current variable's declaration and its initializer

    t_type_ptr  baseType;    // type of scalar or element of array
    int *       dimensions;  // copy of the filed from t_attr_directDeclarator
    int         lenOfDim1;   // length of the first dimension
    int         initorInDim; // the dimension of a sub-initializer

    // During analysing initializer-list of an array,
    // indexHolders[0] holds the dimension(N) of the array,
    // indexHolders[k], 1<=k<=N, holds the current index of dimension k.
    // These holders will be bound to an element of initExprs.
    int  *  indexHolders;

    // All init-value-expressions for an array,
    // the underlying type is list<t_init_expr_ptr>,
    // and will be transfer to a t_attr_directDeclarator
    // and to the symbol-entry of this array finally.
    t_list_ptr  initExprs;
};

extern void stb_stack_push(t_symtable_builder* builderPtr,
                           t_symtable_ptr  symtablePtr,
                           t_funcinfo_ptr  currFuncInfoPtr);
extern t_stack_item_ptr stb_stack_top(t_symtable_builder* builderPtr);
extern void stb_stack_pop(t_symtable_builder* builderPtr);

extern t_funcinfo_ptr stb_new_funcinfo(EnumTokenKind retTypeId,
                                       t_symtable_ptr funcSymTable,
                                       const char * funcName);
extern void stb_free_funcinfo(t_funcinfo_ptr infoPtr);

// Capital names for highlighting
#define SCOPE_STACK_PUSH(builderPtr, symtbl, funInfo)  stb_stack_push(builderPtr, symtbl, funInfo)
#define SCOPE_STACK_POP(builderPtr)     stb_stack_pop(builderPtr)
#define SCOPE_STACK_TOP(builderPtr)     ((t_stack_item_ptr)stb_stack_top(builderPtr))

#define LOG_STEP  log_debug


// -----------------------------------------------------------------------
// Concrete attribute class for declaration of variables
// during build symbol tables
//
typedef struct attrDirectDeclarator {
    t_reference   base;  // base object

//  members of this derived class
    bool        hasError;
    t_tree_ptr  idNode;          // the tree node holding the ID token
    t_tree_ptr  initializerNode; // initializer node under initDeclarator

    // For an array,
    // dimensions[0] holds the dimension(N) of the array,
    // dimensions[k], 1<=k<=N, holds the length of Kth dimension
    int *       dimensions;      // will be passed to symbol entry

// extra members for analysis arrays and their initializer, NOT for parameters

    // all init-values-expression for an array,
    // the underlying type is list<t_init_expr_ptr>,
    // and will be transfer to a t_var_symInfo of an array variable
    t_list_ptr  initExprs;
} t_attr_directDeclarator;

extern t_attr_directDeclarator * new_attr_directDeclarator();

extern void stb_attrset_free(t_map_key K, t_map_value V);


// -----------------------------------------------------------------------
// some helper functions
//

extern t_list_ptr new_init_expr();
extern bool stb_array_checkSize(t_attr_directDeclarator * attr);
extern void array_init_dump(t_symentry_ptr pSymEntry ); // in arr_check.c

extern void stb_allocMemoryForVariable(
                t_symtable_ptr symTable,
                t_type_ptr     varType,
                size_t * pOffset /*output*/ );

extern bool stb_bindVariableReferToDef(t_tree_ptr pReferNode,
                                       t_symentry_ptr pSymEntry,
                                       t_tree_ptr leftValueNode);
extern bool stb_bindLabelReferToDef(t_tree_ptr pReferNode,
                                    t_symentry_ptr pSymEntry);
extern void stb_resolveAllUndefinedLabels(t_list_ptr  undefinedLabels,
                                          t_symtable_ptr funcSymTable);
extern bool stb_bindFunctionReferToDef(t_tree_ptr     pReferNode,
                                       t_symentry_ptr pSymEntry,
                                       t_tree_ptr     pCallNode);
extern void stb_resolveAllUndefinedFunctions(t_list_ptr undefinedFunctions,
                                             t_symtable_ptr symTableStarting);



// -----------------------------------------------------------------------
// Semantic actions for all interesting non-terminals(productions)
//

#define STB_TREEFUNC(fn)  void fn(t_tree_listener_ptr listenerPtr, t_tree_ptr node)

// semantic actions for all declarations
extern STB_TREEFUNC(stb_enter_translationUnit);
extern STB_TREEFUNC(stb_exit_translationUnit);
extern STB_TREEFUNC(stb_enter_functionDeclaration);
extern STB_TREEFUNC(stb_exit_functionDeclaration);
extern STB_TREEFUNC(stb_exit_parameterList);
extern STB_TREEFUNC(stb_enter_parameter);
extern STB_TREEFUNC(stb_exit_parameter);
extern STB_TREEFUNC(stb_enter_variableDeclaration);
extern STB_TREEFUNC(stb_exit_variableDeclaration);
extern STB_TREEFUNC(stb_exit_initDeclarator);
extern STB_TREEFUNC(stb_exit_directDeclarator);
extern STB_TREEFUNC(stb_enter_initializer);
extern STB_TREEFUNC(stb_exit_initializer);

// semantic actions for all statements
extern STB_TREEFUNC(stb_enter_labeledStatement);
extern STB_TREEFUNC(stb_enter_compoundStatement);
extern STB_TREEFUNC(stb_exit_compoundStatement);
extern STB_TREEFUNC(stb_exit_jumpStatement);

// semantic actions for all expressions
extern STB_TREEFUNC(stb_exit_leftValue);
extern STB_TREEFUNC(stb_exit_functionCall);

extern STB_TREEFUNC(stb_exit_expression);
extern STB_TREEFUNC(stb_exit_assignmentExpr);
extern STB_TREEFUNC(stb_exit_logicalOrExpr);
extern STB_TREEFUNC(stb_exit_logicalAndExpr);
extern STB_TREEFUNC(stb_exit_equalityExpr);
extern STB_TREEFUNC(stb_exit_relationalExpr);
extern STB_TREEFUNC(stb_exit_additiveExpr);
extern STB_TREEFUNC(stb_exit_multiplicativeExpr);
extern STB_TREEFUNC(stb_exit_unaryExpr);
extern STB_TREEFUNC(stb_exit_primaryExpr);


AMCC_DECL_END

#endif // #ifndef AMCC__STB_INNER_H
